﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Collections;

namespace Liang.Util
{
    /// <summary>
    /// 压缩解压
    /// </summary>
    public class CompressHelper
    {
        /// <summary>
        /// 压缩流
        /// </summary>
        /// <param name="headers"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static Stream Compress(ITransportHeaders headers, Stream stream)
        {
            MemoryStream resultStream = new MemoryStream();
            GZipStream outStream = new GZipStream(resultStream, CompressionMode.Compress,true);

            byte[] buff = new Byte[10000];
            int count = stream.Read(buff, 0, 10000);
            while (count > 0)
            {
                outStream.Write(buff, 0, count);
                count = stream.Read(buff, 0, 10000);
            }
            outStream.Flush();
            outStream.Close();
            resultStream.Position = 0;
            return resultStream;
        }

        /// <summary>
        /// 解压流
        /// </summary>
        /// <param name="headers"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static Stream UnCompress(ITransportHeaders headers, Stream stream)
        {            
            MemoryStream resultStream = new MemoryStream();
            GZipStream inStream = new GZipStream(stream, CompressionMode.Decompress,true);

            byte[] buff = new byte[10000];
            int count = inStream.Read(buff, 0, 10000);            
            while (count > 0)
            {
                resultStream.Write(buff, 0, count);
                count = inStream.Read(buff, 0, 10000);
            }
            inStream.Close();
            resultStream.Position = 0;
            return resultStream;
        }
    }

    #region ClientCompressSink
        /// <summary>
        /// Client Channel Sink.
        /// </summary>	
        public class ClientCompressSink : BaseChannelWithProperties, IClientChannelSink
        {
            private IClientChannelSink _nextSink;
    
            public IClientChannelSink NextChannelSink
            {
                get
                {
                    return _nextSink;
                }
            }
    
            public ClientCompressSink(IClientChannelSink next)
            {
                _nextSink = next;
            }
    
            public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
                IMessage msg,
                ITransportHeaders headers,
                Stream stream)
            {
                stream = CompressHelper.Compress(headers, stream); //compress request stream
                sinkStack.Push(this, null); //put self to stack for later use(in response).
                _nextSink.AsyncProcessRequest(sinkStack, msg, headers, stream); //forward to next sink.
            }
    
            public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,
                object state,
                ITransportHeaders headers,
                Stream stream)
            {
                stream = CompressHelper.UnCompress(headers, stream); //uncompress response stream.
                sinkStack.AsyncProcessResponse(headers, stream); //forward to next sink.
            }
    
            public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
            {
                return _nextSink.GetRequestStream(msg, headers);
            }
    
            public void ProcessMessage(IMessage msg,
                ITransportHeaders requestHeaders,
                Stream requestStream,
                out ITransportHeaders responseHeaders,
                out Stream responseStream)
            {
                requestStream = CompressHelper.Compress(requestHeaders, requestStream); 
                  //compress request stream.
                _nextSink.ProcessMessage(msg, requestHeaders, requestStream, out responseHeaders, 
                                     out responseStream); //forward to next sink.
                responseStream = CompressHelper.UnCompress(responseHeaders, responseStream); 
                  //uncompress response stream.
            }
        }
        #endregion
    
        #region ClientCompressSinkProvider
        /// <summary>
        /// Client Channel Sink Provider.
        /// </summary>	
        public class ClientCompressSinkProvider : IClientChannelSinkProvider
        {
            private IClientChannelSinkProvider _nextProvider;
    
            public IClientChannelSinkProvider Next
            {
                get
                {
                    return _nextProvider;
                }
                set
                {
                    _nextProvider = value;
                }
            }
    
            public ClientCompressSinkProvider(IDictionary properties, ICollection providerData)
            {
            }
    
            public IClientChannelSink CreateSink(IChannelSender channel, string url, 
                               object remoteChannelData)
            {
                IClientChannelSink next = _nextProvider.CreateSink(channel, url, remoteChannelData);                        
                return new ClientCompressSink(next);
            }
        }
        #endregion
    
    
        #region ServerCompressSink
        /// <summary>
        /// Server Channel Sink
        /// </summary>	
        public class ServerCompressSink : BaseChannelWithProperties, IServerChannelSink
        {
            private IServerChannelSink _nextSink;
    
            public IServerChannelSink NextChannelSink
            {
               get
                {
                    return _nextSink;
                }
            }
    
            public ServerCompressSink(IServerChannelSink next)
            {
                _nextSink = next;
            }
    
            public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack,
                object state,
                IMessage msg,
                ITransportHeaders headers,
                Stream stream)
            {
                CompressHelper.Compress(headers, stream);
                sinkStack.AsyncProcessResponse(msg, headers, stream);
            }
   
            public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack,
                object state,
                IMessage msg,
                ITransportHeaders headers)
            {
                return null;
            }
    
            public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
                IMessage requestMsg,
                ITransportHeaders requestHeaders,
                Stream requestStream,
                out IMessage responseMsg,
                out ITransportHeaders responseHeaders,
                out Stream responseStream)
            {
                requestStream = CompressHelper.UnCompress(requestHeaders, requestStream);
                sinkStack.Push(this, null);
                ServerProcessing retval = _nextSink.ProcessMessage(sinkStack, requestMsg, 
                             requestHeaders, requestStream, out responseMsg, out responseHeaders, 
                            out responseStream);
                responseStream = CompressHelper.Compress(responseHeaders, responseStream);
                return retval;
            }
        }
       #endregion   
       #region ServerCompressSinkProvider
        /// <summary>
        /// Client Channel Sink Provider.
        /// </summary>	
        public class ServerCompressSinkProvider : IServerChannelSinkProvider
        {
            private IServerChannelSinkProvider _nextProvider;
    
            public IServerChannelSinkProvider Next
            {
                get
                {
                    return _nextProvider;
                }
                set
                {
                    _nextProvider = value;
                }
            }
    
            public ServerCompressSinkProvider(IDictionary properties, ICollection providerData)
            {
            }
    
            public IServerChannelSink CreateSink(IChannelReceiver channel)
            {
                IServerChannelSink next = _nextProvider.CreateSink(channel);
                return new ServerCompressSink(next);
            }
    
            public void GetChannelData(IChannelDataStore channelData)
            {
            }
        }
        #endregion
    }

